﻿using StarPizza.Model.BaseModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StarPizza.Model.Core
{
    public class StockHandler : IIngredientResource, IStorageManipulator
    {
        Stock stock;
        StorageHandler virtualStorage;
        CashRegister cashRegister;

        public StockHandler(Stock stock, CashRegister cashRegister)
        {
            this.stock = stock;
            //we work with the same ingredients but our own amounts
            virtualStorage = stock.CloneStorage();

            this.cashRegister = cashRegister;

            this.DoughStorageChanged += new DoughStorageChangedEventHandler(
                (dough, diff, newAmount) =>
                {
                    if (newAmount == 0)
                    {
                        if (OutOfDough != null)
                            OutOfDough(dough);
                    }
                    else if (newAmount - diff == 0)
                    {
                        if (DoughBecameAvailable != null)
                            DoughBecameAvailable(dough);
                    }
                });
            this.ToppingStorageChanged += new ToppingStorageChangedEventHandler(
                (topping, diff, newAmount) =>
                {
                    if (newAmount == 0)
                    {
                        if (OutOfTopping != null)
                            OutOfTopping(topping);
                    }
                    else if (newAmount - diff == 0)
                    {
                        if (ToppingBecameAvailable != null)
                            ToppingBecameAvailable(topping);
                    }
                });
        }
    
        //IIngredientResource:
        public event Action<Dough> DoughCreated;
        public event DoughStorageChangedEventHandler DoughStorageChanged;
        public event Action<Dough> OutOfDough;
        public event Action<Dough> DoughBecameAvailable;

        public event Action<Topping> ToppingCreated;
        public event ToppingStorageChangedEventHandler ToppingStorageChanged;
        public event Action<Topping> OutOfTopping;
        public event Action<Topping> ToppingBecameAvailable;
    
        public int GetAmount(Ingredient ingredient)
        {
            return virtualStorage.GetAmount(ingredient);
        }
        public bool IsIngredientAvailable(Ingredient ingredient)
        {
            return virtualStorage.GetAmount(ingredient) > 0;
        }
        public bool IsPizzaTemplateOrderable(IPizzaTemplate pizzaTemplate)
        {
            return pizzaTemplate.Toppings.All(
                topping => virtualStorage.GetAmount(topping) > 0);
        }
        public IEnumerable<Topping> GetToppings()
        {
            return stock.GetToppings();
        }
        public IEnumerable<Dough> GetDoughs()
        {
            return stock.GetDoughs();
        }
        
        //IStorageManipulator:
        public void ReserveIngredients(IPizza pizza)
        {
            ChangeIngredientAmounts(pizza, diff: -1);
        }
        public void FreeUpIngredients(IPizza pizza)
        {
            ChangeIngredientAmounts(pizza, diff: +1);
        }
        public void PerformAmountChange()
        {
            stock.PerformStorageChange(virtualStorage);
        }
        public void SupplyTopping(Topping topping, int incoming)
        {
            int newAmount = SupplyIngredient(topping, incoming, topping.Cost);
            if (ToppingStorageChanged != null)
                ToppingStorageChanged(topping, incoming, newAmount);
        }
        public void SupplyDough(Dough dough, int incoming)
        {
            int newAmount = SupplyIngredient(dough, incoming, cost: dough.Cost);
            if (DoughStorageChanged != null)
                DoughStorageChanged(dough, incoming, newAmount);
        }
        private void ChangeIngredientAmounts(IPizza pizza, int diff)
        {
            int newPizzaAmount = virtualStorage.ChangeAmount(pizza.Dough, diff);
            if (DoughStorageChanged != null)
                DoughStorageChanged(pizza.Dough, diff, newPizzaAmount);
            foreach (var topping in pizza.Toppings)
            {
                int newToppingAmount = virtualStorage.ChangeAmount(topping, diff);
                if (ToppingStorageChanged != null)
                    ToppingStorageChanged(topping, diff, newToppingAmount);
            }
        }
        private int SupplyIngredient(Ingredient ingredient, int incoming, int cost)
        {
            cashRegister.Cash -= cost * incoming;
            int newAmount = virtualStorage.ChangeAmount(ingredient, diff: incoming);
            PerformAmountChange();
            return newAmount;
        }
        
        //Other:
        public void CreateTopping(string name, int cost, int price)
        {
            var topping = new Topping
            {
                Name = name,
                Cost = cost,
                Price = price
            };
            if (stock.AddNewTopping(topping))
            {
                virtualStorage.SetAmount(topping, amount: 0);
                if (ToppingCreated != null)
                    ToppingCreated(topping);
            }
            else
            {
                throw new Exception("StockHandler failed to CreateTopping!");
                //TODO we have got a serious issue
            }
        }
        public void CreateDough(int size, int cost, int price)
        {
            var dough = new Dough
            {
                Size = size,
                Cost = cost,
                Price = price
            };
            if (stock.AddNewDough(dough))
            {
                virtualStorage.SetAmount(dough, amount: 0);
                if (DoughCreated != null)
                    DoughCreated(dough);
            }
            else
            {
                throw new Exception("StockHandler failed to CreateDough!");
                //TODO we have got a serious issue
            }
        }
    }
}
